package mapper

// 使用方法
// 在继承的子mapper中继承该父mapper，并实现getDb()方法的重写，如：
//func (testMapper *TestMapper) getDb() *TestMapper {
//	testMapper.db = testMapper.GetModel(new(models.CaseLabelLog).TableName())
//	return testMapper
//}
//err := caseLogMapper.getDb().GetPage(&list, &models.CaseLabelLog{}, field, filter.Page, filter.Limit, &total, whereOrder...)
//err := caseLogMapper.getDb().Find(&list, &models.CaseLabelLog{}, field, 0, whereOrder...)
//err := caseLogMapper.getDb().Last(&list, &models.CaseLabelLog{CaseId: 1234}, field)
//err := caseLogMapper.getDb().Scan(&list, &models.CaseLabelLog{CaseId: 1234}, field, 0)
//err := caseLogMapper.getDb().Last(&list, &models.CaseLabelLog{CaseId: 1234}, field)

import (
	"fmt"
	"github.com/jinzhu/gorm"
	"mall-api-gin/models"
	bizcode "mall-api-gin/pkg/bizerror"
	"mall-api-gin/pkg/logging"
	"reflect"
	"strings"
)

type PageWhereOrder struct {
	Order string
	Where string
	Value []interface{}
}

type Mapper interface {
	GetModel(tableName string) gorm.DB

	Insert(model interface{}) error

	Update(model interface{}) error

	Delete(model interface{}) error

	Scan(out interface{}, where interface{}, cols []string, limit int64, whereOrder ...PageWhereOrder) error

	Transaction(invoker func(tx *gorm.DB) error) (err error)

	UpdateWithOut(where interface{}, value interface{}, out interface{}, selectFields ...[]string) error

	First(out interface{}, where interface{}, cols []string) (bool, error)

	Last(out interface{}, where interface{}, cols []string) (notFound bool, err error)

	Find(out interface{}, where interface{}, selectFields []string, limit int64, whereOrder ...PageWhereOrder) error
}

type BaseMapper struct {
	Db gorm.DB
}

var db *gorm.DB

func initMapper() *gorm.DB {
	db := models.Db()
	_ = BaseMapper{Db: *db}
	return db
}

func (baseMapper *BaseMapper) GetModel(tableName string) gorm.DB {
	return *initMapper().Table(tableName)
}

func (baseMapper *BaseMapper) GetDb() *BaseMapper {
	return baseMapper
}

// Transaction 事物处理
func (baseMapper *BaseMapper) Transaction(invoker func(tx *gorm.DB) error) (err error) {
	tx := models.Db()
	err = tx.Transaction(invoker)
	bizcode.DbCheck(err)
	return
}

// Insert 插入数据
func (baseMapper *BaseMapper) Insert(model interface{}) error {
	err := baseMapper.GetDb().Db.Create(model).Error
	if err != nil {
		logging.Error("插入数据错误：%#v", model)
	}
	bizcode.DbCheck(err)
	fmt.Printf("返回数据：%#v", model)
	return err
}

// Update 更新数据
func (baseMapper *BaseMapper) Update(model interface{}) error {
	err := baseMapper.GetDb().Db.Updates(model).Error
	bizcode.DbCheck(err)
	return err
}

// UpdateWithOut 更新并返回
// 用法
// where := models.Licence{Model: models.Model{ID: 14}}
// updateDta := models.Licence{Valid: 2}
// out := models.Licence{}
// err := service.LicenceService.GetMapper().UpdateWithOut(&where, &updateDta, &out)
func (baseMapper *BaseMapper) UpdateWithOut(where interface{}, value interface{}, out interface{}, selectFields ...[]string) error {
	db := baseMapper.GetDb().Db.Where(where)
	err := db.Updates(value).Error
	if err != nil {
		return err
	}
	if len(selectFields) > 0 {
		return db.Select(selectFields[0]).Find(out).Error
	}
	return db.Find(out).Error
}

// Delete 删除
func (baseMapper *BaseMapper) Delete(model interface{}) error {
	err := baseMapper.GetDb().Db.Delete(model).Error
	return err
}

// First 查询一条通过主键ASC排序的第一条数据
// out：返回字段，调用:&models.modelName{}
// where：为查询条件 调用：&models.modelName{Key:value}
// cols 查询字段
func (baseMapper *BaseMapper) First(out interface{}, where interface{}, cols []string) (notFound bool, err error) {
	db := baseMapper.GetDb().Db.Where(where)
	if len(cols) > 0 {
		db = db.Select(cols)
	}
	err = db.First(out).Error
	if err != nil {
		notFound = gorm.IsRecordNotFoundError(err)
		if !notFound {
			bizcode.DbCheck(err)
		}
	}
	return
}

// Last 获取最后一条通过主键DESC排序的数据
// out：返回字段，调用:&models.modelName{}
// where：为查询条件 调用：&models.modelName{Key:value}
func (baseMapper *BaseMapper) Last(out interface{}, where interface{}, cols []string) (notFound bool, err error) {
	db := baseMapper.GetDb().Db.Where(where)
	if len(cols) > 0 {
		db = db.Select(cols)
	}
	err = db.Last(out).Error
	if err != nil {
		notFound = gorm.IsRecordNotFoundError(err)
		if !notFound {
			bizcode.DbCheck(err)
		}
	}
	return
}

// Count 统计
func (baseMapper *BaseMapper) Count(where interface{}) (int64, error) {
	var count int64
	err := baseMapper.GetDb().Db.Where(where).Count(&count).Error
	return count, err
}

// GetWhereOrder 获得查询条件和排序
func (baseMapper *BaseMapper) GetWhereOrder(db *gorm.DB, whereOrder ...PageWhereOrder) *gorm.DB {
	if len(whereOrder) > 0 {
		for _, wo := range whereOrder {
			if wo.Order != "" {
				db = db.Order(wo.Order)
			}
			if wo.Where != "" {
				db = db.Where(wo.Where, wo.Value...)
			}
		}
	}
	return db
}

// Scan 获取多行数据
// out 返回数据 用法：var res []*models.modelName  Scan(&res)
// where 条件查询 调用：&models.modelName{Key:value}  或者是map
// cols 字段
// whereOrder 拼接where语句和order语句
func (baseMapper *BaseMapper) Scan(out interface{}, where interface{}, cols []string, limit int64, whereOrder ...PageWhereOrder) error {
	db := baseMapper.GetDb().Db.Where(where)
	db = baseMapper.GetWhereOrder(db, whereOrder...)
	if limit > 0 {
		db = db.Limit(limit)
	}
	if len(cols) > 0 {
		db = db.Select(cols)
	}
	err := db.Scan(out).Error
	if err != nil && !gorm.IsRecordNotFoundError(err) {
		bizcode.DbCheck(err)
	}
	return err
}

// Find 获取多条数据
// out：返回字段，调用:&models.modelName{}
// where：为查询条件 调用：&models.modelName{Key:value} 或者是map
func (baseMapper *BaseMapper) Find(out interface{}, where interface{}, selectFields []string, limit int64, whereOrder ...PageWhereOrder) error {
	db := baseMapper.GetDb().Db.Where(where)
	db = baseMapper.GetWhereOrder(db, whereOrder...)
	if limit > 0 {
		db = db.Limit(limit)
	}
	if len(selectFields) > 0 {
		db = db.Select(selectFields)
	}
	err := db.Find(out).Error
	if err != nil && !gorm.IsRecordNotFoundError(err) {
		bizcode.DbCheck(err)
	}
	return err
}

// WhereOp 拼接操作
func (baseMapper *BaseMapper) WhereOp(param interface{}, field string, op string) *PageWhereOrder {
	paramType := reflect.TypeOf(param)
	paramValue := reflect.ValueOf(param)
	if paramType.Kind().String() == "string" {
		if paramValue.String() != "" {
			var arr []interface{}
			value := paramValue.String()
			op = strings.ToUpper(op)
			if op == "LIKE" {
				value = "%" + value + "%"
			}
			arr = append(arr, value)
			return &PageWhereOrder{Where: fmt.Sprintf("%v %v ?", field, op), Value: arr}
		}
	} else if paramType.Kind().String() == "int" || paramType.Kind().String() == "int64" {
		if !paramValue.IsZero() {
			var arr []interface{}
			arr = append(arr, paramValue.Int())
			return &PageWhereOrder{Where: fmt.Sprintf("%v %v ?", field, op), Value: arr}
		}
	}
	return nil
}

// WhereEq 等于
func (baseMapper *BaseMapper) WhereEq(param interface{}, field string) *PageWhereOrder {
	return baseMapper.WhereOp(param, field, "=")
}

// WhereNEq 不等于
func (baseMapper *BaseMapper) WhereNEq(param interface{}, field string) *PageWhereOrder {
	return baseMapper.WhereOp(param, field, "<>")
}

// WhereGT 大于
func (baseMapper *BaseMapper) WhereGT(param interface{}, field string) *PageWhereOrder {
	return baseMapper.WhereOp(param, field, ">")
}

// WhereEGT 大于等于
func (baseMapper *BaseMapper) WhereEGT(param interface{}, field string) *PageWhereOrder {
	return baseMapper.WhereOp(param, field, ">=")
}

// WhereLT 小于
func (baseMapper *BaseMapper) WhereLT(param interface{}, field string) *PageWhereOrder {
	return baseMapper.WhereOp(param, field, "<")
}

// WhereELT 小于等于
func (baseMapper *BaseMapper) WhereELT(param interface{}, field string) *PageWhereOrder {
	return baseMapper.WhereOp(param, field, "<=")
}

// WhereLike LIKE
func (baseMapper *BaseMapper) WhereLike(param interface{}, field string) *PageWhereOrder {
	return baseMapper.WhereOp(param, field, "LIKE")
}

// WhereOrder ORDER排序
func (baseMapper *BaseMapper) WhereOrder(orderKey string) *PageWhereOrder {
	if orderKey != "" {
		return &PageWhereOrder{Order: orderKey}
	}
	return nil
}

// GetPage 获取分页数据
// var userList []models.User
// var field []string
// var total *uint64
// var whereOrder mapper.PageWhereOrder
// 用法：GetPage(&userList, &models.User{}, field, 1, 10, &total, whereOrder)
func (baseMapper *BaseMapper) GetPage(out interface{}, where interface{}, field []string, pageIndex, pageSize uint64, totalCount *uint64, whereOrder ...PageWhereOrder) error {
	db := baseMapper.GetDb().Db.Where(where)
	db = baseMapper.GetWhereOrder(db, whereOrder...)
	err := db.Count(totalCount).Error
	if err != nil {
		return err
	}
	if *totalCount == 0 {
		return nil
	}
	db = db.Offset((pageIndex - 1) * pageSize).Limit(pageSize)
	if len(field) > 0 {
		db = db.Select(field)
	}
	err = db.Find(out).Error
	if err != nil && !gorm.IsRecordNotFoundError(err) {
		bizcode.DbCheck(err)
	}
	return err
}

// Save 保存 如果不存在主键，则做插入操作，否则做更新操作
func (baseMapper *BaseMapper) Save(value interface{}) error {
	return baseMapper.GetDb().Db.Save(value).Error
}
